const crypto = require('crypto');
const { Project, Section, Form, ProjectVersion } = require('../models');

// 生成快照（最小闭包，供并排预览与轻量对比）
async function buildSnapshot(projectId) {
  const project = await Project.findById(projectId);
  if (!project) throw new Error('项目未找到');

  // sections（按项目配置顺序）
  const sections = [];
  const sorted = (project.configSections || []).sort((a,b) => (a.order||0)-(b.order||0));
  for (const sc of sorted) {
    const section = await Section.findById(sc.sectionId).populate({ path: 'forms', options: { sort: { order: 1 } } });
    if (!section) continue;
    sections.push({
      _id: section._id,
      name: section.name,
      order: sc.order,
      forms: (section.forms || []).map(f => ({
        _id: f._id,
        name: f.name,
        order: f.order,
        fields: Array.isArray(f.config?.fields) ? f.config.fields.map(ff => ({
          id: ff.id || ff._id,
          type: ff.type,
          value: pickFieldInfo(ff.value)
        })) : []
      }))
    });
  }

  // frontMatter（直接返回项目里的配置）
  const frontMatter = (project.frontMatter || []).map(i => ({
    formId: i.formId,
    order: i.order,
    customTitle: i.customTitle || '',
    showInToc: !!i.showInToc,
    tocLevel: [1,2].includes(i.tocLevel) ? i.tocLevel : 1,
    hideFormTitle: !!i.hideFormTitle,
    pageBreakAfter: !!i.pageBreakAfter
  }));

  return {
    project: { _id: project._id, name: project.name, protocolNumber: project.protocolNumber },
    frontMatter,
    sections
  };
}

function pickFieldInfo(v = {}) {
  const out = {};
  if (!v || typeof v !== 'object') return out;
  const keys = ['label','fieldName','suffix','placeholder','description','helpText','signatureLabel','dateLabel','innerText'];
  for (const k of keys) if (v[k] !== undefined) out[k] = v[k];
  if (Array.isArray(v.options)) {
    out.options = v.options.map(o => ({ id: o.id || o.value, text: o.text || o.label })).filter(Boolean);
  }
  if (Array.isArray(v.columns)) {
    out.columns = v.columns.map(c => ({ id: c.id, title: c.title, type: c.type, options: Array.isArray(c.options)?c.options.map(o=>({label:o.label,value:o.value})):undefined }));
  }
  if (Array.isArray(v.rows)) {
    out.rows = v.rows.map(r => ({ id: r.id }));
  }
  return out;
}

// 发布版本
exports.publish = async (req, res) => {
  try {
    const { id: projectId } = req.params;
    const { versionTag, description } = req.body || {};
    if (!versionTag) return res.status(400).json({ success:false, message:'版本号必填' });

    const snapshot = await buildSnapshot(projectId);
    const hash = crypto.createHash('sha1').update(JSON.stringify(snapshot)).digest('hex');

    const doc = await ProjectVersion.create({
      projectId,
      versionTag,
      description: description || '',
      publishedBy: req.user?._id,
      snapshot,
      snapshotHash: hash
    });

    res.json({ success:true, message:'发布成功', data:{ id: doc._id, versionTag: doc.versionTag } });
  } catch (e) {
    if (e.code === 11000) return res.status(400).json({ success:false, message:'版本号已存在' });
    res.status(500).json({ success:false, message:'发布失败', error: e.message });
  }
};

// 版本列表
exports.list = async (req, res) => {
  try {
    const { id: projectId } = req.params;
    const list = await ProjectVersion.find({ projectId }).sort({ publishedAt: -1 }).select('versionTag description publishedAt');
    res.json(list);
  } catch (e) {
    res.status(500).json({ success:false, message:'获取版本列表失败', error: e.message });
  }
};

// 获取单个版本
exports.getOne = async (req, res) => {
  try {
    const { versionId } = req.params;
    const doc = await ProjectVersion.findById(versionId);
    if (!doc) return res.status(404).json({ success:false, message:'版本不存在' });
    res.json({ snapshot: doc.snapshot, versionTag: doc.versionTag, publishedAt: doc.publishedAt });
  } catch (e) {
    res.status(500).json({ success:false, message:'获取版本失败', error: e.message });
  }
};

// 轻量对比：返回 changedIds + summary
exports.compare = async (req, res) => {
  try {
    const { baseVersionId, targetVersionId } = req.body || {};
    const [base, target] = await Promise.all([
      ProjectVersion.findById(baseVersionId),
      ProjectVersion.findById(targetVersionId)
    ]);
    if (!base || !target) return res.status(400).json({ success:false, message:'版本不存在' });

    const result = diffSnapshots(base.snapshot, target.snapshot);
    res.json(result);
  } catch (e) {
    res.status(500).json({ success:false, message:'对比失败', error: e.message });
  }
};

function diffSnapshots(a, b) {
  const changes = {
    sections: { added: [], removed: [], modified: [], reordered: false },
    forms: { added: [], removed: [], modified: [] },
    fields: { added: [], removed: [], modified: [] },
    frontMatters: { added: [], removed: [], modified: [], reordered: false }
  };
  const summary = { added: 0, removed: 0, modified: 0, reordered: 0 };

  // 前置页：按 formId 对比
  const aFM = (a.frontMatter||[]).map(x=>String(x.formId));
  const bFM = (b.frontMatter||[]).map(x=>String(x.formId));
  const fmAdded = bFM.filter(x=>!aFM.includes(x));
  const fmRemoved = aFM.filter(x=>!bFM.includes(x));
  changes.frontMatters.added.push(...fmAdded);
  changes.frontMatters.removed.push(...fmRemoved);
  summary.added += fmAdded.length; summary.removed += fmRemoved.length;
  if (!arraysEqualOrder(aFM,bFM)) { summary.reordered += 1; changes.frontMatters.reordered = true; }

  // sections by _id
  const aSec = (a.sections||[]).map(s=>String(s._id));
  const bSec = (b.sections||[]).map(s=>String(s._id));
  const secAdded = bSec.filter(x=>!aSec.includes(x));
  const secRemoved = aSec.filter(x=>!bSec.includes(x));
  changes.sections.added.push(...secAdded);
  changes.sections.removed.push(...secRemoved);
  summary.added += secAdded.length; summary.removed += secRemoved.length;
  if (!arraysEqualOrder(aSec,bSec)) { summary.reordered += 1; changes.sections.reordered = true; }

  // section 名称变更（交集部分）
  const commonSec = intersect(aSec, bSec);
  for (const sid of commonSec) {
    const aName = (a.sections||[]).find(s=>String(s._id)===sid)?.name || '';
    const bName = (b.sections||[]).find(s=>String(s._id)===sid)?.name || '';
    if (aName !== bName) { changes.sections.modified.push(sid); summary.modified++; }
  }

  // forms and fields
  const aForms = indexForms(a.sections||[]);
  const bForms = indexForms(b.sections||[]);

  const formIds = new Set([...Object.keys(aForms), ...Object.keys(bForms)]);
  for (const fid of formIds) {
    if (!aForms[fid]) { changes.forms.added.push(fid); summary.added++; continue; }
    if (!bForms[fid]) { changes.forms.removed.push(fid); summary.removed++; continue; }
    const aF = aForms[fid], bF = bForms[fid];
    // 名称修改
    if ((aF.name||'') !== (bF.name||'')) { changes.forms.modified.push(fid); summary.modified++; }
    // 字段对比（仅文本性信息）
    const aFields = indexFields(aF.fields||[]);
    const bFields = indexFields(bF.fields||[]);
    const fids = new Set([...Object.keys(aFields), ...Object.keys(bFields)]);
    for (const id of fids) {
      if (!aFields[id]) { changes.fields.added.push(id); summary.added++; continue; }
      if (!bFields[id]) { changes.fields.removed.push(id); summary.removed++; continue; }
      if (!shallowEqual(aFields[id], bFields[id])) { changes.fields.modified.push(id); summary.modified++; }
    }
  }

  // 向后兼容：扁平化 changedIds（仅用于老前端高亮）
  const changedIds = {
    sections: unique([...changes.sections.added, ...changes.sections.removed, ...changes.sections.modified]),
    forms: unique([...changes.forms.added, ...changes.forms.removed, ...changes.forms.modified]),
    fields: unique([...changes.fields.added, ...changes.fields.removed, ...changes.fields.modified]),
    frontMatters: unique([...changes.frontMatters.added, ...changes.frontMatters.removed, ...changes.frontMatters.modified])
  };
  return { summary, changedIds, changes };
}

function indexForms(sections){
  const map = {};
  for (const s of sections){
    for (const f of (s.forms||[])) map[String(f._id)] = { name: f.name, fields: f.fields };
  }
  return map;
}
function indexFields(fields){
  const map = {};
  for (const f of fields){ map[String(f.id)] = f.value || {}; }
  return map;
}
function intersect(a,b){ const setB=new Set(b); return a.filter(x=>setB.has(x)); }
function unique(arr){ return Array.from(new Set(arr)); }
function arraysEqualOrder(a,b){
  if (a.length!==b.length) return false; for(let i=0;i<a.length;i++) if (a[i]!==b[i]) return false; return true;
}
function shallowEqual(a,b){
  const ka = Object.keys(a||{}); const kb = Object.keys(b||{});
  if (ka.length!==kb.length) return false;
  for (const k of ka){ if (Array.isArray(a[k]) && Array.isArray(b[k])){
      if (a[k].length!==b[k].length) return false;
      for (let i=0;i<a[k].length;i++){
        const av=a[k][i], bv=b[k][i];
        if (av?.text!==bv?.text && av?.label!==bv?.label) return false;
      }
    } else if (a[k]!==b[k]) return false; }
  return true;
}


